"""
第一课：类型提示实战练习代码
配合 01_type_hints.md 讲义使用

运行方式：
cd /Users/baimu/PycharmProjects/fastApiProject3
python lessons/01_type_hints_practice.py
"""

from typing import Optional, Union, List, Dict, Tuple, Set, Any, Callable

print("=" * 50)
print("第一部分：基础类型提示")
print("=" * 50)


# 1. 基本类型提示
def greet(name: str) -> str:
    """问候函数"""
    return f"Hello {name}"


name: str = "张三"
age: int = 25
height: float = 175.5
is_student: bool = True

print(f"姓名: {name}, 年龄: {age}, 身高: {height}cm, 是学生: {is_student}")
print(f"问候: {greet(name)}")


# 2. 函数参数和返回值
def add(a: int, b: int) -> int:
    """加法函数"""
    return a + b


def divide(a: float, b: float) -> float:
    """除法函数"""
    if b == 0:
        return 0.0
    return a / b


print(f"\n3 + 5 = {add(3, 5)}")
print(f"10 / 2 = {divide(10, 2)}")

print("\n" + "=" * 50)
print("第二部分：容器类型提示")
print("=" * 50)


# 3. 列表类型提示
def get_even_numbers(numbers: list[int]) -> list[int]:
    """获取偶数列表"""
    return [n for n in numbers if n % 2 == 0]


numbers: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = get_even_numbers(numbers)
print(f"原始列表: {numbers}")
print(f"偶数列表: {even_numbers}")


# 4. 字典类型提示
def get_student_info(student_id: int) -> dict[str, str | int]:
    """获取学生信息"""
    students = {
        1: {"name": "张三", "age": 20, "major": "计算机"},
        2: {"name": "李四", "age": 21, "major": "数学"},
    }
    return students.get(student_id, {})


student = get_student_info(1)
print(f"\n学生信息: {student}")


# 5. 元组类型提示
def get_coordinate() -> tuple[float, float]:
    """获取坐标"""
    return (10.5, 20.3)


coordinate: tuple[float, float] = get_coordinate()
print(f"坐标: x={coordinate[0]}, y={coordinate[1]}")


# 6. 集合类型提示
def get_unique_tags(items: list[dict[str, Any]]) -> set[str]:
    """获取所有唯一标签"""
    tags: set[str] = set()
    for item in items:
        if "tags" in item:
            tags.update(item["tags"])
    return tags


items = [
    {"name": "商品1", "tags": ["电子", "数码"]},
    {"name": "商品2", "tags": ["数码", "手机"]},
    {"name": "商品3", "tags": ["电子", "电脑"]},
]
unique_tags = get_unique_tags(items)
print(f"\n所有标签: {unique_tags}")

print("\n" + "=" * 50)
print("第三部分：可选类型与联合类型")
print("=" * 50)


# 7. Optional 类型
def greet_user(name: str | None = None) -> str:
    """可选参数的问候函数"""
    if name:
        return f"你好，{name}！"
    return "你好，访客！"


print(greet_user("张三"))
print(greet_user())


# 8. Union 类型
def process_id(user_id: int | str) -> str:
    """处理用户ID（可以是整数或字符串）"""
    return f"处理用户ID: {user_id} (类型: {type(user_id).__name__})"


print(f"\n{process_id(123)}")
print(f"{process_id('USER_456')}")


# 9. 多个类型的联合
def format_value(value: int | str | float | bool) -> str:
    """格式化各种类型的值"""
    if isinstance(value, bool):
        return "是" if value else "否"
    elif isinstance(value, int):
        return f"整数: {value}"
    elif isinstance(value, float):
        return f"浮点数: {value:.2f}"
    else:
        return f"字符串: {value}"


print(f"\n{format_value(42)}")
print(f"{format_value(3.14159)}")
print(f"{format_value('Hello')}")
print(f"{format_value(True)}")

print("\n" + "=" * 50)
print("第四部分：复杂类型提示")
print("=" * 50)


# 10. 嵌套类型
def analyze_scores(
    student_scores: dict[str, list[int]]
) -> dict[str, dict[str, float]]:
    """分析学生成绩"""
    result: dict[str, dict[str, float]] = {}

    for student, scores in student_scores.items():
        if scores:
            result[student] = {
                "平均分": sum(scores) / len(scores),
                "最高分": float(max(scores)),
                "最低分": float(min(scores)),
            }

    return result


scores_data = {"张三": [85, 90, 78], "李四": [92, 88, 95], "王五": [70, 75, 80]}

analysis = analyze_scores(scores_data)
print("\n成绩分析:")
for student, stats in analysis.items():
    print(f"{student}: {stats}")


# 11. Callable 类型
def execute_operation(
    func: Callable[[int, int], int], a: int, b: int, operation_name: str
) -> None:
    """执行数学运算"""
    result = func(a, b)
    print(f"{operation_name}: {a} 和 {b} = {result}")


def multiply(x: int, y: int) -> int:
    """乘法"""
    return x * y


def subtract(x: int, y: int) -> int:
    """减法"""
    return x - y


print("\n数学运算:")
execute_operation(multiply, 6, 7, "乘法")
execute_operation(subtract, 10, 3, "减法")

print("\n" + "=" * 50)
print("第五部分：类型别名")
print("=" * 50)


# 12. 类型别名简化复杂类型
UserId = int
UserName = str
User = dict[str, str | int]
UserList = list[User]


def create_user(user_id: UserId, name: UserName, age: int) -> User:
    """创建用户"""
    return {"id": user_id, "name": name, "age": age}


def get_all_users() -> UserList:
    """获取所有用户"""
    return [
        create_user(1, "张三", 25),
        create_user(2, "李四", 30),
        create_user(3, "王五", 28),
    ]


users = get_all_users()
print("\n用户列表:")
for user in users:
    print(f"  ID: {user['id']}, 姓名: {user['name']}, 年龄: {user['age']}")

print("\n" + "=" * 50)
print("第六部分：类中的类型提示")
print("=" * 50)


# 13. 类的类型提示
class Student:
    """学生类"""

    name: str
    age: int
    scores: list[int]
    teacher: str | None

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age
        self.scores = []
        self.teacher = None

    def add_score(self, score: int) -> None:
        """添加成绩"""
        self.scores.append(score)

    def get_average(self) -> float:
        """计算平均分"""
        if not self.scores:
            return 0.0
        return sum(self.scores) / len(self.scores)

    def set_teacher(self, teacher: str) -> None:
        """设置老师"""
        self.teacher = teacher

    def __str__(self) -> str:
        """字符串表示"""
        avg = self.get_average()
        return f"学生: {self.name}, {self.age}岁, 平均分: {avg:.1f}, 老师: {self.teacher or '未分配'}"


# 创建学生对象
student1 = Student("赵六", 20)
student1.add_score(85)
student1.add_score(90)
student1.add_score(88)
student1.set_teacher("王老师")

print(f"\n{student1}")

print("\n" + "=" * 50)
print("第七部分：实战练习")
print("=" * 50)


# 练习 1：BMI 计算器
def calculate_bmi(height: float, weight: float) -> float:
    """计算BMI指数"""
    return weight / (height**2)


def get_bmi_category(bmi: float) -> str:
    """获取BMI分类"""
    if bmi < 18.5:
        return "偏瘦"
    elif bmi < 24:
        return "正常"
    elif bmi < 28:
        return "偏胖"
    else:
        return "肥胖"


print("\n练习 1: BMI 计算器")
height_m = 1.75
weight_kg = 70
bmi_value = calculate_bmi(height_m, weight_kg)
category = get_bmi_category(bmi_value)
print(f"身高: {height_m}m, 体重: {weight_kg}kg")
print(f"BMI: {bmi_value:.2f}, 分类: {category}")


# 练习 2：成绩过滤器
def get_passing_scores(scores: list[int], passing_grade: int = 60) -> list[int]:
    """获取及格成绩"""
    return [s for s in scores if s >= passing_grade]


def get_score_statistics(scores: list[int]) -> dict[str, float]:
    """获取成绩统计"""
    if not scores:
        return {"平均分": 0.0, "最高分": 0.0, "最低分": 0.0}

    return {
        "平均分": sum(scores) / len(scores),
        "最高分": float(max(scores)),
        "最低分": float(min(scores)),
    }


print("\n练习 2: 成绩分析")
all_scores = [45, 78, 92, 58, 66, 88, 34, 95]
passing = get_passing_scores(all_scores)
stats = get_score_statistics(all_scores)

print(f"所有成绩: {all_scores}")
print(f"及格成绩: {passing}")
print(f"统计信息: {stats}")


# 练习 3：用户信息格式化
def format_user_info(
    user: dict[str, str | int], include_age: bool = True
) -> str:
    """格式化用户信息"""
    name = user.get("name", "未知")
    result = f"姓名: {name}"

    if include_age and "age" in user:
        result += f", 年龄: {user['age']}岁"

    if "email" in user:
        result += f", 邮箱: {user['email']}"

    return result


print("\n练习 3: 用户信息格式化")
user1 = {"name": "张三", "age": 25, "email": "zhang@example.com"}
user2 = {"name": "李四", "age": 30}

print(format_user_info(user1))
print(format_user_info(user2))
print(format_user_info(user1, include_age=False))


# 练习 4：购物车系统
class ShoppingCart:
    """购物车类"""

    items: list[dict[str, str | float | int]]
    discount: float

    def __init__(self, discount: float = 0.0) -> None:
        self.items = []
        self.discount = discount

    def add_item(self, name: str, price: float, quantity: int = 1) -> None:
        """添加商品"""
        self.items.append({"name": name, "price": price, "quantity": quantity})

    def get_total(self) -> float:
        """计算总价"""
        total = sum(
            float(item["price"]) * int(item["quantity"]) for item in self.items
        )
        return total * (1 - self.discount)

    def get_item_count(self) -> int:
        """获取商品数量"""
        return sum(int(item["quantity"]) for item in self.items)

    def __str__(self) -> str:
        """字符串表示"""
        return f"购物车: {self.get_item_count()}件商品, 总价: ¥{self.get_total():.2f}"


print("\n练习 4: 购物车系统")
cart = ShoppingCart(discount=0.1)  # 9折优惠
cart.add_item("笔记本电脑", 5999.0, 1)
cart.add_item("鼠标", 99.0, 2)
cart.add_item("键盘", 299.0, 1)

print(cart)
print(f"商品明细:")
for item in cart.items:
    print(
        f"  {item['name']}: ¥{item['price']} x {item['quantity']} = ¥{float(item['price']) * int(item['quantity']):.2f}"
    )

print("\n" + "=" * 50)
print("🎉 恭喜！你已完成类型提示的所有练习")
print("=" * 50)
print("\n核心要点回顾:")
print("1. 类型提示提高代码可读性和可维护性")
print("2. FastAPI 依赖类型提示实现自动验证")
print("3. 使用 list[T], dict[K, V] 标注容器类型")
print("4. 使用 | None 或 Optional 表示可选类型")
print("5. 使用类型别名简化复杂类型")
print("\n准备好继续学习「异步编程」了吗？")

